/* test_mutex_trylock_1():
		A simple test that does:
			* Creates two additional threads: 1,2.
			* Thread 2 locks a global lock.
			* Thread 1 trys to lock the global lock - and fails.
			* Thread 1 trys to unlock the global lock - and fails.
			* Thread 2 trys to lock the global lock (succeeds).
			* Thread 2 unlocks the lock 3 times (fails the third time).
			* Thread 0 does 'join' to threads 1,2.
*/


#include <assert.h>
#include <stdio.h>
#include <stdbool.h>
#include "test_general.h"

#include "user_threads.h"
#include "user_mutex.h"


bool test_mutex_trylock_1();


#define THREADS_NUM 3
uthread_mutex_t global_mutex;


static int thread1_start_routine(void * param) {

	if ( (*((int*)param)) != 53) {
		return -1;
	}
	some_long_operation(1.0);
	int tmp;
	tmp = uthread_mutex_try_lock(global_mutex);
	if (tmp != MUTEX_LOCKED) {
		return -1;
	}

	tmp = uthread_mutex_unlock(global_mutex);
	if (tmp != MUTEX_LOCKED) {

		return -1;
	}

	thread_ok[1] = true;
	return 3;
}

static int thread2_start_routine(void * param) {

	if ( (*((int*)param)) != 53) {
		return -1;
	}
	some_long_operation(0.1);
	int tmp;
	tmp = uthread_mutex_try_lock(global_mutex);
	if (tmp != MUTEX_SUCCESS) { 
		return -1;
	}
	
	some_long_operation(1.5);

	tmp = uthread_mutex_try_lock(global_mutex);
	//if (tmp != MUTEX_SUCCESS) {
	if (tmp != MUTEX_LOCKED) {
		return -1;
	}


	tmp = uthread_mutex_unlock(global_mutex);
	if (tmp != MUTEX_SUCCESS) {
		return -1;
	}

	tmp = uthread_mutex_unlock(global_mutex);
	if (tmp != MUTEX_UNLOCKED) {
		return -1;
	}

	tmp = uthread_mutex_unlock(global_mutex);
	if (tmp != MUTEX_UNLOCKED) {
		return -1;
	}

	thread_ok[2] = true;
	return 8;
}


bool test_mutex_trylock_1()
{
	init_individual_test();


	int tmp;


	 if(initilize_uthread_in_each_test) {
		tmp = uthread_init();
		TEST_ASSERT(tmp == UTHREAD_SUCCESS);
	}

	tmp = uthread_mutex_init(&global_mutex);
	TEST_ASSERT(tmp == MUTEX_SUCCESS);

	thread_id threads[THREADS_NUM];

	threads[0] = uthread_self();
	TEST_ASSERT(threads[0] == 0);

	int FiftyThree = 53;
	
	threads[1] = uthread_create(thread1_start_routine, &FiftyThree);
	TEST_ASSERT(threads[1] == 1);
	
	threads[2] = uthread_create(thread2_start_routine, &FiftyThree);
	
	TEST_ASSERT(threads[2] == 2);

	some_long_operation(3.0);
	
	tmp = uthread_mutex_destroy(global_mutex);
	TEST_ASSERT(tmp == MUTEX_SUCCESS);


	int tmp2;
	tmp = uthread_join(threads[1],&tmp2);
	TEST_ASSERT(UTHREAD_SUCCESS == tmp);
	TEST_ASSERT(3 == tmp2);

	tmp = uthread_join(threads[2],&tmp2);
	TEST_ASSERT(UTHREAD_SUCCESS == tmp);
	TEST_ASSERT(8 == tmp2);


	thread_ok[0] = true;
	TEST_ASSERT(are_all_threads_ok(THREADS_NUM));

	return true;
}
